home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / pascal / oo123.exe / OO123.PAS < prev   
Encoding:
Pascal/Delphi Source File  |  1993-03-16  |  27.3 KB  |  831 lines

  1. Unit OO123;
  2.  
  3. (*
  4.    Over the last year we've lurked behind the scenes here, enjoying
  5.    the fruits of your labours.
  6.  
  7.    It seemed time to give something back, so here's a unit that will
  8.    enable you to create Lotus 1-2-3 V2.x compatible models quickly
  9.    and easily via OOP.  We use the TurboPower Object Professional 
  10.    date routines but any julian date routine will work if you change
  11.    TDateCell.Init.  If you don't have any date routines, just UNDEF
  12.    USEDATES.
  13.  
  14.    Here's a simple test program:-
  15.  
  16.    Program Test;
  17.  
  18.    {$N+,E+}
  19.  
  20.    Uses Objects, OO123;
  21.  
  22.    Var   P123 : PModel;
  23.          PD   : PDateCell;
  24.          PT   : PTextCell;
  25.          PN   : PNumericCell;
  26.          Y    : Word;
  27.    Begin
  28.       P123:=New(PModel, Init('TEST.WK1'));
  29.       If P123<>NIL then with P123^ do
  30.       Begin
  31.          PT:=AddTextCell('..Date..');
  32.          AddTextCell('Refce')^.JustRight;
  33.          AddTextCell('Amount')^.JustRight;
  34.          AddTextCell('Narration');
  35.          NewRow;
  36.          NewRow;
  37.          For Y:=1 to 100 do
  38.          Begin
  39.             PD:=AddDateCell('1/03/93');
  40.             PN:=AddNumericCell(Y);
  41.             PN:=AddNumericCell(100.00);
  42.             PT:=AddTextCell('This is a narration');
  43.             PT:=AddTextCell('');
  44.             If PT^.Value<>NIL then DisposeStr(PT^.Value);
  45.             PT^.Value:=NewStr('This is cell '+PT^.Reference);
  46.             NewRow;
  47.          end;
  48.          SetColumnWidth(3,30);
  49.          SetColumnWidth(4,30);
  50.          Save;
  51.          Dispose(P123, Done);
  52.       end;
  53.    end.
  54.  
  55.    PS: If you're wondering why there isn't a type TExpressionCell it's
  56.    because I've never figured out expression encoding.  There's a simple
  57.    workaround: just prefix each expression with a special character
  58.    (say '|'), then run the following Lotus 1-2-3 macro:-
  59.  
  60.    ------------------------------------------------------------------------
  61.  
  62.    \A       {indicate Formula Conversion..}{paneloff}{windowsoff}
  63.             /rncHERE~{bs}~
  64.             {home}
  65.             /rncWORKAREA~{bs}.{end}{home}~
  66.             {for WIDTH,1,@cols(WORKAREA),1,LOOP1}
  67.             {goto}HERE~
  68.             /rndWORKAREA~/rndHERE~
  69.             {indicate}
  70.  
  71.    LOOP1    {for HEIGHT,1,@rows(WORKAREA),1,LOOP2}
  72.             {right}{up HEIGHT-1}
  73.  
  74.    LOOP2    {if @cellpointer("type")<>"l"}{down}{return}
  75.             {if @length(@cellpointer("contents"))=0}/re~/rfr~{down}{return}
  76.             {if @left(@cellpointer("contents"),1)<>"|"}{down}{return}
  77.             {edit}{home}{del}{del}~
  78.             {down}
  79.  
  80.    WIDTH           8
  81.    HEIGHT         25
  82.  
  83.    ERRCHECK @code(@cellpointer)
  84.  
  85.    ------------------------------------------------------------------------
  86.  
  87.    If you know how to create a TExpressionCell the hard way, and you
  88.    wouldn't mind sharing your knowledge, then please feel free to e-mail
  89.    us.
  90.  
  91.    Enjoy...
  92.  
  93.    Steve Agnew
  94.    CIS 70032,2240
  95.  
  96. *)
  97.  
  98. {$D-,S-,R-,L-,N+,E+}
  99.  
  100. {$DEFINE USEDATES}
  101.  
  102. INTERFACE
  103.  
  104. Uses Objects, DOS 
  105.      {$IFDEF USEDATES} , OpDate {$ENDIF}
  106.      ;
  107.  
  108. CONST
  109.    fProtected  = $80;
  110.    fFixed      = $00;
  111.    fScientific = $10;
  112.    fCurrency   = $20;
  113.    fPercent    = $30;
  114.    fComma      = $40;
  115.    fSpecial    = $70;
  116.    fGeneral    = $01;
  117.    fDMY        = $02;
  118.    fDM         = $03;
  119.    fMY         = $04;
  120.    fText       = $05;
  121.  
  122. TYPE
  123.    PCell  = ^TCell;
  124.    TCell  = Object(TObject)
  125.                CellType   : Word;
  126.                CellLength : Word;
  127.                CellFormat : Byte;
  128.                CellColumn : Word;
  129.                CellRow    : Word;
  130.                Constructor Init(AType, AColumn, ARow : Word);
  131.                Procedure   SetFormat(AFormat : Byte);
  132.                Procedure   Write(Var S : TBufStream); VIRTUAL;
  133.                Function    Reference: String;
  134.             end;
  135.  
  136.    { -------------------------------------------------------------------- }
  137.  
  138.    PNumericCell  = ^TNumericCell;
  139.    TNumericCell  = Object(TCell)
  140.                       Value : Double;
  141.                       Constructor Init(AColumn, ARow : Word; AValue : Double);
  142.                       Procedure   Write(Var S : TBufStream); VIRTUAL;
  143.                    end;
  144.  
  145.    { -------------------------------------------------------------------- }
  146.  
  147.    PCurrencyCell  = ^TCurrencyCell;
  148.    TCurrencyCell  = Object(TCell)
  149.                       Value : Double;
  150.                       Constructor Init(AColumn, ARow : Word; AValue : Double);
  151.                       Procedure   Write(Var S : TBufStream); VIRTUAL;
  152.                    end;
  153.  
  154. {$IFDEF USEDATES}
  155.    { -------------------------------------------------------------------- }
  156.    PDateCell     = ^TDateCell;
  157.    TDateCell     = Object(TCell)
  158.                       Value : Double;
  159.                       Constructor Init(AColumn, ARow : Word; AValue : String);
  160.                       Procedure   Write(Var S : TBufStream); VIRTUAL;
  161.                    end;
  162. {$ENDIF}
  163.    { -------------------------------------------------------------------- }
  164.  
  165.    PTextCell  = ^TTextCell;
  166.    TTextCell  = Object(TCell)
  167.                       Just  : Char;
  168.                       Value : PString;
  169.                       Constructor Init(AColumn, ARow : Word; AValue : String);
  170.                       Procedure   Write(Var S : TBufStream); VIRTUAL;
  171.                       Procedure   JustLeft;
  172.                       Procedure   JustCentre;
  173.                       Procedure   JustRight;
  174.                       Destructor  Done; VIRTUAL;
  175.                    end;
  176.  
  177.    { -------------------------------------------------------------------- }
  178.  
  179.    PCellCollection = ^TCellCollection;
  180.    TCellCollection = Object(TSortedCollection)
  181.                        function  Compare(Key1, Key2: Pointer): Integer; VIRTUAL;
  182.                        function  FindCell(Col, Row : Word): Pointer;
  183.                        Procedure Write(Var S: TBufStream); VIRTUAL;
  184.                      end;
  185.  
  186.    { -------------------------------------------------------------------- }
  187.  
  188.    ColumnInfo = Record
  189.                    First    : Word;
  190.                    Last     : Word;
  191.                    Width    : Byte;
  192.                 end;
  193.  
  194.    PModel = ^TModel;
  195.    TModel = Object(TObject)
  196.                FileName : PathStr;
  197.                Cells    : PCellCollection;
  198.             PRIVATE
  199.                MaxRows  : Word;
  200.                MaxCols  : Word;
  201.                Row      : Word;
  202.                Col      : Word;
  203.                ColHdr   : Array[0..255] of ColumnInfo;
  204.             PUBLIC
  205.                Constructor Init(AFileName : PathStr);
  206.                Procedure   Save;
  207.                Procedure   NewRow;
  208.                Procedure   NewColumn;
  209.                Function    AddNumericCell (AValue : Double): PNumericCell;
  210.                Function    AddCurrencyCell (AValue : Double): PCurrencyCell;
  211.                {$IFDEF USEDATES}
  212.                Function    AddDateCell    (AValue : String): PDateCell;
  213.                {$ENDIF}
  214.                Function    AddTextCell    (AValue : String): PTextCell;
  215.                Procedure   SetColumnWidth (Column,Width: Word);
  216.                Function    FindCell(AColumn, ARow : Word): Pointer;
  217.                Destructor  Done; VIRTUAL;
  218.             end;
  219.  
  220.    { -------------------------------------------------------------------- }
  221.  
  222.  
  223. IMPLEMENTATION
  224.  
  225. Function NumToStr(N: LongInt): String;
  226. Var S : String;
  227. Begin
  228.    Str(N,S);
  229.    NumToStr:=S;
  230. end;
  231.  
  232. {  =============================[ TCELL ]============================ }
  233.  
  234. Constructor TCell.Init(AType, AColumn, ARow : Word);
  235.  
  236. Begin
  237.    If not Inherited Init then FAIL;
  238.    CellType    := AType;
  239.    CellColumn  := AColumn;
  240.    CellRow     := ARow;
  241.    CellFormat  := $71;
  242. end;
  243.    
  244. { -------------------------------------------------------------------- }
  245.  
  246. Procedure TCell.SetFormat(AFormat : Byte);
  247. Begin
  248.    CellFormat  := AFormat;
  249. end;   
  250.  
  251. { -------------------------------------------------------------------- }
  252.  
  253. Procedure TCell.Write(Var S : TBufStream);
  254. Begin
  255.    Abstract;
  256. end;
  257.  
  258. { -------------------------------------------------------------------- }
  259.  
  260. Function TCell.Reference: String;
  261.  
  262.    Function MakeRef( x1,y1 : Integer): String;
  263.  
  264.    Var
  265.       S : String[10];
  266.    begin
  267.       S:='';
  268.       If x1>26 then
  269.       begin
  270.          S:=S+Chr(((x1-1) div 26)+64);
  271.          S:=S+Chr(((x1-1) mod 26)+65);
  272.          If y1>0 then S:=S+NumToStr(y1);
  273.       end
  274.       else
  275.       begin
  276.          If x1>0 then S:=S+Chr(x1+64);
  277.          If y1>0 then S:=S+NumToStr(y1);
  278.       end;
  279.       MakeRef:=S;
  280.    end;
  281.  
  282. Begin
  283.    Reference:=MakeRef(CellColumn+1, CellRow+1);
  284. end;
  285.  
  286. {  ==========================[ TNUMERICCELL ]========================= }
  287.  
  288. Constructor TNumericCell.Init(AColumn, ARow : Word; AValue : Double);
  289.  
  290. Begin
  291.    If not Inherited Init($0E,AColumn,ARow) then FAIL;
  292.    Value:=AValue;
  293. end;
  294.  
  295. { -------------------------------------------------------------------- }
  296.  
  297. Procedure TNumericCell.Write (Var S : TBufStream);
  298.  
  299. Begin
  300.    CellLength:=13;
  301.    S.Write( CellType   , Sizeof( CellType   ));
  302.    S.Write( CellLength , Sizeof( CellLength ));
  303.    S.Write( CellFormat , Sizeof( CellFormat ));
  304.    S.Write( CellColumn , Sizeof( CellColumn ));
  305.    S.Write( CellRow    , Sizeof( CellRow    ));
  306.    S.Write( Value      , Sizeof( Value      ));
  307. end;
  308.  
  309. {  ==========================[ TCURRENCYCELL ]========================= }
  310.  
  311. Constructor TCurrencyCell.Init(AColumn, ARow : Word; AValue : Double);
  312.  
  313. Begin
  314.    If not Inherited Init($0E,AColumn,ARow) then FAIL;
  315.    Value:=AValue;
  316.    CellFormat:=$22;
  317. end;
  318.  
  319. { -------------------------------------------------------------------- }
  320.  
  321. Procedure TCurrencyCell.Write (Var S : TBufStream);
  322.  
  323. Begin
  324.    CellLength:=13;
  325.    S.Write( CellType   , Sizeof( CellType   ));
  326.    S.Write( CellLength , Sizeof( CellLength ));
  327.    S.Write( CellFormat , Sizeof( CellFormat ));
  328.    S.Write( CellColumn , Sizeof( CellColumn ));
  329.    S.Write( CellRow    , Sizeof( CellRow    ));
  330.    S.Write( Value      , Sizeof( Value      ));
  331. end;
  332.  
  333. {$IFDEF USEDATES}
  334.  
  335. {  ==========================[ TDATECELL ]========================= }
  336.  
  337. Constructor TDateCell.Init(AColumn, ARow : Word; AValue : String);
  338.  
  339. Var ADate : Double;
  340.     NewDate : Date;
  341.     RefDate : Date;
  342. Begin
  343.    If not Inherited Init($0E,AColumn,ARow) then FAIL;
  344.    RefDate := DMYToDate(1,3,93);
  345.    NewDate := DateStringtoDate('DD/MM/YY',AValue);
  346.    Value   := 34029.0 { Lotus Representation of 01-03-93 }
  347.               + (NewDate - RefDate);
  348.    CellFormat:=$F2;
  349. end;
  350.  
  351. { -------------------------------------------------------------------- }
  352.  
  353. Procedure TDateCell.Write (Var S : TBufStream);
  354.  
  355. Begin
  356.    CellLength:=13;
  357.    S.Write( CellType   , Sizeof( CellType   ));
  358.    S.Write( CellLength , Sizeof( CellLength ));
  359.    S.Write( CellFormat , Sizeof( CellFormat ));
  360.    S.Write( CellColumn , Sizeof( CellColumn ));
  361.    S.Write( CellRow    , Sizeof( CellRow    ));
  362.    S.Write( Value      , Sizeof( Value      ));
  363. end;
  364.  
  365. {$ENDIF}
  366. {  ==========================[ TALPHACELL ]========================= }
  367.  
  368. Constructor TTextCell.Init(AColumn, ARow : Word; AValue : String);
  369.  
  370. Begin
  371.    If not Inherited Init($0F,AColumn,ARow) then FAIL;
  372.    Value:=NewStr(AValue);
  373.    Just:=#$27;
  374. end;
  375.  
  376. { -------------------------------------------------------------------- }
  377.  
  378. Procedure TTextCell.JustLeft;
  379.  
  380. Begin Just:=#$27; end; { ' }
  381.  
  382. { -------------------------------------------------------------------- }
  383.  
  384. Procedure TTextCell.JustCentre;
  385.  
  386. Begin Just:='^'; end;
  387.  
  388. { -------------------------------------------------------------------- }
  389.  
  390. Procedure TTextCell.JustRight;
  391.  
  392. Begin Just:='"'; end;
  393.  
  394. { -------------------------------------------------------------------- }
  395.  
  396. Destructor TTextCell.Done;
  397.  
  398. Begin
  399.    If Value<>NIL then DisposeStr(Value);
  400.    Value:=NIL;
  401.    Inherited Done;
  402. end;
  403.  
  404. { -------------------------------------------------------------------- }
  405.  
  406. Procedure TTextCell.Write (Var S : TBufStream);
  407.  
  408. Var V : String;
  409.     E : Byte;
  410.  
  411. Begin
  412.    V:=''; If Value<>NIL then V:=Value^;
  413.    CellLength:=7+Length(V);
  414.    S.Write( CellType   , Sizeof( CellType   ));
  415.    S.Write( CellLength , Sizeof( CellLength ));
  416.    S.Write( CellFormat , Sizeof( CellFormat ));
  417.    S.Write( CellColumn , Sizeof( CellColumn ));
  418.    S.Write( CellRow    , Sizeof( CellRow    ));
  419.    S.Write( Just       , Sizeof( Just       ));
  420.    If Length(V)>0 then S.Write( V[1], Length(V) );
  421.    E:=0;   
  422.    S.Write( E          , Sizeof( E ));
  423. end;
  424.  
  425. {  ==========================[ TCELLCOLLECTION ]========================= }
  426.  
  427. function TCellCollection.Compare(Key1, Key2: Pointer): Integer;
  428.  
  429. Var C1 : PCell absolute Key1;
  430.     C2 : PCell absolute Key2;
  431. Begin
  432.    if C1^.CellRow < C2^.CellRow then Begin Compare := -1; exit; end;
  433.    if C1^.CellRow > C2^.CellRow then Begin Compare :=  1; exit; end;
  434.    { Same Row }
  435.    if C1^.CellColumn < C2^.CellColumn then Begin Compare := -1; exit; end;
  436.    if C1^.CellColumn > C2^.CellColumn then Begin Compare :=  1; exit; end;
  437.    Compare:=0;
  438. end;
  439.  
  440. { -------------------------------------------------------------------- }
  441.  
  442. function TCellCollection.FindCell(Col, Row: Word): Pointer;
  443.  
  444.    Function Matches(P : PCell): Boolean; FAR;
  445.  
  446.    Begin
  447.       Matches:=(P^.CellColumn=Col) AND (P^.CellRow = Row);
  448.    end;
  449.  
  450. Begin
  451.    FindCell:=FirstThat(@Matches);
  452. end;
  453.    
  454. { -------------------------------------------------------------------- }
  455.  
  456. Procedure TCellCollection.Write(Var S: TBufStream);
  457.  
  458.    Function WriteCell(P : PCell): Boolean; FAR;
  459.  
  460.    Begin
  461.       P^.Write(S);
  462.    end;
  463.  
  464. Begin
  465.    ForEach(@WriteCell);
  466. end;
  467.    
  468. {  ==========================[ TMODEL ]========================= }
  469.  
  470. Constructor TModel.Init(AFileName : PathStr);
  471.  
  472. Begin
  473.    If not Inherited Init then FAIL;
  474.    FileName := AFileName;
  475.    Cells:=New(PCellCollection, Init(100,50));
  476.    If Cells=NIL then FAIL;
  477. end;
  478.  
  479. {  ------------------------------------------------------------------  }
  480.  
  481. Procedure TModel.NewRow;
  482.  
  483. Begin
  484.    Inc(Row);
  485.    Col:=0;
  486. end;
  487.  
  488. {  ------------------------------------------------------------------  }
  489.  
  490. Procedure TModel.NewColumn;
  491.  
  492. Begin
  493.    Inc(Col);
  494. end;
  495.  
  496. {  ------------------------------------------------------------------  }
  497.  
  498. Function TModel.AddNumericCell(AValue : Double): PNumericCell;
  499.  
  500. Var P : PNumericCell;
  501.  
  502. Begin
  503.    P:=New(PNumericCell, Init(Col, Row, AValue));
  504.    If P<>NIL then
  505.    Begin
  506.       Cells^.Insert(P);
  507.       If ColHdr[Col].Width<15 then ColHdr[Col].Width:=15;
  508.       If (Row < ColHdr[Col].First) then ColHdr[Col].First:=Row;
  509.       If (Row > ColHdr[Col].Last ) then ColHdr[Col].Last :=Row;
  510.       If Row>MaxRows then MaxRows:=Row;
  511.       If Col>MaxCols then MaxCols:=Col;
  512.       Inc(Col);
  513.    end;
  514.    AddNumericCell:=P;
  515. end;
  516.  
  517. {  ------------------------------------------------------------------  }
  518.  
  519. Function TModel.AddCurrencyCell(AValue : Double): PCurrencyCell;
  520.  
  521. Var P : PCurrencyCell;
  522.  
  523. Begin
  524.    P:=New(PCurrencyCell, Init(Col, Row, AValue));
  525.    If P<>NIL then
  526.    Begin
  527.       Cells^.Insert(P);
  528.       If ColHdr[Col].Width<15 then ColHdr[Col].Width:=15;
  529.       If (Row < ColHdr[Col].First) then ColHdr[Col].First:=Row;
  530.       If (Row > ColHdr[Col].Last ) then ColHdr[Col].Last :=Row;
  531.       If Row>MaxRows then MaxRows:=Row;
  532.       If Col>MaxCols then MaxCols:=Col;
  533.       Inc(Col);
  534.    end;
  535.    AddCurrencyCell:=P;
  536. end;
  537.  
  538. {  ------------------------------------------------------------------  }
  539. {$IFDEF USEDATES}
  540. Function TModel.AddDateCell(AValue : String): PDateCell;
  541.  
  542. Var P : PDateCell;
  543.  
  544. Begin
  545.    P:=New(PDateCell, Init(Col, Row, AValue));
  546.    If P<>NIL then
  547.    Begin
  548.       Cells^.Insert(P);
  549.       If ColHdr[Col].Width<10 then ColHdr[Col].Width:=10;
  550.       If (Row < ColHdr[Col].First) then ColHdr[Col].First:=Row;
  551.       If (Row > ColHdr[Col].Last ) then ColHdr[Col].Last :=Row;
  552.       If Row>MaxRows then MaxRows:=Row;
  553.       If Col>MaxCols then MaxCols:=Col;
  554.       Inc(Col);
  555.    end;
  556.    AddDateCell:=P;
  557. end;
  558. {$ENDIF}
  559. {  ------------------------------------------------------------------  }
  560.  
  561. Function TModel.AddTextCell(AValue : String): PTextCell;
  562.  
  563. Var P : PTextCell;
  564.  
  565. Begin
  566.    P:=New(PTextCell, Init(Col, Row, AValue));
  567.    If P<>NIL then
  568.    Begin
  569.       Cells^.Insert(P);
  570.       If ColHdr[Col].Width<(Length(AValue)+2) then ColHdr[Col].Width:=Length(AValue)+2;
  571.       If (Row < ColHdr[Col].First) then ColHdr[Col].First:=Row;
  572.       If (Row > ColHdr[Col].Last ) then ColHdr[Col].Last :=Row;
  573.       If Row>MaxRows then MaxRows:=Row;
  574.       If Col>MaxCols then MaxCols:=Col;
  575.       Inc(Col);
  576.    end;
  577.    AddTextCell:=P;
  578. end;
  579.  
  580. {  ------------------------------------------------------------------  }
  581.  
  582. Procedure TModel.SetColumnWidth(Column,Width: Word);
  583.  
  584. Begin
  585.    ColHdr[Column].Width:=Width;
  586. end;   
  587.  
  588. {  ------------------------------------------------------------------  }
  589.  
  590. Function TModel.FindCell(AColumn, ARow : Word): Pointer;
  591.  
  592. Begin
  593.    FindCell:=Cells^.FindCell(AColumn, ARow);
  594. end;
  595.  
  596. {  ------------------------------------------------------------------  }
  597.  
  598. Procedure TModel.Save;
  599.  
  600. TYPE
  601.    b1   = Byte;
  602.    b2   = Array[1..2] of Byte;
  603.    b4   = Array[1..4] of Byte;
  604.    b5   = Array[1..5] of Byte;
  605.    b6   = Array[1..6] of Byte;
  606.    b7   = Array[1..7] of Byte;
  607.    b8   = Array[1..8] of Byte;
  608.    b12  = Array[1..12] of Byte;
  609.    b14  = Array[1..14] of Byte;
  610.    b17  = Array[1..17] of Byte;
  611.    b20  = Array[1..20] of Byte;
  612.    b29  = Array[1..29] of Byte;
  613.    b36  = Array[1..36] of Byte;
  614.    b44  = Array[1..44] of Byte;
  615.  
  616. CONST
  617.    _BOF           : b6 =  ($00, $00, $02, $00, $06, $04); { Lotus 1-2-3 Rel 2 }
  618.    _EOF           : b4 =  ($01, $00, $00, $00);           { End of File Marker }
  619.    _CALCMODE      : b5 =  ($02, $00, $01, $00, $00);      { Manual Calculation }
  620.    _CALCCOUNT     : b5 =  ($2F, $00, $01, $00, $01);      { Calculation Count }
  621.    _CALCORDER     : b5 =  ($03, $00, $01, $00, $00);      { Natural Order }
  622.    _SPLIT         : b5 =  ($04, $00, $01, $00, $00);      { Window not Split }
  623.    _SYNCH         : b5 =  ($05, $00, $01, $00, $00);      { Window not Synchronised }
  624.  
  625.    _RANGE         : b8 =  ($06, $00, $08, $00, $00, $00, $00, $00);
  626.  
  627.    __WINDOW1      : b36 = ($07, $00, $20, $00,           { Window 1 Description }
  628.                                      $00, $00,           { Current Cursor Column }
  629.                                      $00, $00,           { Current Cursor Row }
  630.                                      $00,                { Cell Format Byte }
  631.                                      $00,                { Unused }
  632.                                      $00, $00,           { Column Width }
  633.                                      $00, $00,           { Number of Columns on Screen }
  634.                                      $00, $00,           { Number of Rows on Screen }
  635.                                      $00, $00,           { Leftmost Column }
  636.                                      $00, $00,           { Top Row }
  637.                                      $00, $00,           { Number of Title Columns }
  638.                                      $00, $00,           { Number of Title Rows }
  639.                                      $00, $00,           { Left Title Column }
  640.                                      $00, $00,           { Left Title Row }
  641.                                      $00, $00,           { Border Width Column }
  642.                                      $00, $00,           { Border Width Row }
  643.                                      $00, $00,           { Window Width }
  644.                                      $00, $00 );          { Unused }
  645.  
  646.    _COLW1         : b4  = ($08, $00, $03, $00 );         { Set Column Width }
  647.  
  648.    _HIDVEC1       : b36 = ($64, $00, $20, $00,           { Hidden Columns }
  649.                            $00, $00, $00, $00,
  650.                            $00, $00, $00, $00,
  651.                            $00, $00, $00, $00,
  652.                            $00, $00, $00, $00,
  653.                            $00, $00, $00, $00,
  654.                            $00, $00, $00, $00,
  655.                            $00, $00, $00, $00,
  656.                            $00, $00, $00, $00 );
  657.  
  658.    _TABLE         : b29 = ($18, $00, $19, $00,          { Table Range }
  659.                            $00, $FF, $FF, $FF,
  660.                            $FF, $FF, $FF, $FF,
  661.                            $FF, $FF, $FF, $FF,
  662.                            $FF, $FF, $FF, $FF,
  663.                            $FF, $FF, $FF, $FF,
  664.                            $FF, $FF, $FF, $FF,
  665.                            $FF );
  666.  
  667.    _QRANGE        : b29 = ($19, $00, $19, $00,          { Query Range }
  668.                            $FF, $FF, $FF, $FF,
  669.                            $FF, $FF, $FF, $FF,
  670.                            $FF, $FF, $FF, $FF,
  671.                            $FF, $FF, $FF, $FF,
  672.                            $FF, $FF, $FF, $FF,
  673.                            $FF, $FF, $FF, $FF,
  674.                            $00 );
  675.  
  676.    _PRANGE        : b12=  ($1A, $00, $08, $00,           { Print Range }
  677.                                      $FF, $FF,           { Start Column }
  678.                                      $00, $00,           { Start Row }
  679.                                      $FF, $FF,           { End Column }
  680.                                      $00, $00 );         { End Row }
  681.  
  682.    _UNFORMATTED   : b5 =  ($30, $00, $01, $00, $00);    { Unformatted Printing }
  683.  
  684.    _FRANGE        : b12 = ($1C, $00, $08, $00,          { Fill Range }
  685.                                      $FF, $FF,          { Start Column }
  686.                                      $FF, $FF,          { Start Row }
  687.                                      $FF, $FF,          { End Column }
  688.                                      $FF, $FF );        { End Row }
  689.  
  690.    _SRANGE        : b12 = ($1B, $00, $08, $00,          { Sort Range }
  691.                                      $00, $00,          { Start Column }
  692.                                      $FF, $FF,          { Start Row }
  693.                                      $00, $00,          { End Column }
  694.                                      $00, $00 );        { End Row }
  695.  
  696.    _RRANGE        : b29 = ($19, $00, $19, $00,          { Query Range }
  697.                            $FF, $FF, $FF, $FF,
  698.                            $FF, $FF, $FF, $FF,
  699.                            $FF, $FF, $FF, $FF,
  700.                            $FF, $FF, $FF, $FF,
  701.                            $FF, $FF, $FF, $FF,
  702.                            $FF, $FF, $FF, $FF,
  703.                            $00 );
  704.  
  705.    _MATRIXRANGE   : b44 = ($69, $00, $28, $00,          { Matrix Range }
  706.                            $FF, $FF, $FF, $FF,
  707.                            $FF, $FF, $FF, $FF,
  708.                            $FF, $FF, $FF, $FF,
  709.                            $FF, $FF, $FF, $FF,
  710.                            $FF, $FF, $FF, $FF,
  711.                            $FF, $FF, $FF, $FF,
  712.                            $FF, $FF, $FF, $FF,
  713.                            $FF, $FF, $FF, $FF,
  714.                            $FF, $FF, $FF, $FF,
  715.                            $FF, $FF, $FF, $FF );
  716.  
  717.    _HRANGE        : b20 = ($20, $00, $10, $00,          { Distribution Range }
  718.                                      $FF, $FF,          { Values Range Start Column }
  719.                                      $FF, $FF,          { Values Range Start Row }
  720.                                      $FF, $FF,          { Values Range End Column }
  721.                                      $FF, $FF,          { Values Range End Row }
  722.                                      $FF, $FF,          { Bin Range Start Column }
  723.                                      $FF, $FF,          { Bin Range Start Row }
  724.                                      $FF, $FF,          { Bin Range Start Column }
  725.                                      $FF, $FF );        { Bin Range Start Row }
  726.  
  727.    _GPROTECT      : b5 =  ($24, $00, $01, $00, $00);    { Global Protection }
  728.  
  729.    _MARGINS       : b14 = ($28, $00, $0A, $00,          { Margin Settings }
  730.                                      $0A, $00,          { Left Margin }
  731.                                      $49, $00,          { Right Margin }
  732.                                      $42, $00,          { Page Length }
  733.                                      $06, $00,          { Top Margin }
  734.                                      $06, $00 );        { Bottom Margin }
  735.  
  736.    _LABELFMT      : b5  = ($29, $00, $01, $00, $27);    { Label Alignment }
  737.  
  738.    _TITLES        : b20 = ($2A, $00, $10, $00,          { Print Borders }
  739.                                      $FF, $FF,          { Row Border Start Column }
  740.                                      $00, $00,          { Row Border Start Row }
  741.                                      $FF, $FF,          { Row Border End Column }
  742.                                      $00, $00,          { Row Border End Row }
  743.                                      $FF, $FF,          { Column Border Start Column }
  744.                                      $00, $00,          { Column Border Start Row }
  745.                                      $FF, $FF,          { Column Border Start Column }
  746.                                      $00, $00 );        { Column Border Start Row }
  747.  
  748. Var S : TBufStream; B,X : Byte; L,W : Word;
  749.  
  750. Begin { TModel.Save }
  751.    S.Init(FileName, stCreate, 1024);
  752.    If S.Status=stOK then
  753.    Begin
  754.       S.Write( _BOF    , Sizeof( _BOF ));
  755.       S.Write( _RANGE  , Sizeof( _RANGE ));
  756.       S.Write( MaxCols , Sizeof( MaxCols ));
  757.       S.Write( MaxRows , Sizeof( MaxRows ));
  758.              
  759.       L:=0;
  760.       For x:=0 to MaxCols do 
  761.          if (ColHdr[x].Last<>0) OR
  762.             (ColHdr[x].Width<>0)
  763.       then l:=l+6;
  764.  
  765.       X:=$96; S.Write( X, Sizeof( X ));
  766.       X:=$00; S.Write( X, Sizeof( X ));
  767.       S.Write( L, Sizeof( L ));
  768.       For W:=0 to MaxCols do
  769.          if (ColHdr[W].Last<>0) OR
  770.             (ColHdr[W].Width<>0) Then
  771.       Begin
  772.          S.Write( W, Sizeof( W ));
  773.          S.Write( ColHdr[W].First , Sizeof( Word ));
  774.          S.Write( ColHdr[W].Last  , Sizeof( Word ));
  775.       End;
  776.          
  777.       S.Write( _CALCCOUNT , Sizeof( _CALCCOUNT ));
  778.       S.Write( _CALCMODE  , Sizeof( _CALCMODE  ));
  779.       S.Write( _CALCORDER , Sizeof( _CALCORDER ));
  780.       S.Write( _SPLIT     , Sizeof( _SPLIT     ));
  781.       S.Write( _SYNCH     , Sizeof( _SYNCH     ));
  782.  
  783.       For W:=0 to MaxCols do
  784.          if (ColHdr[W].Last<>0) OR
  785.             (ColHdr[W].Width<>0) Then
  786.       Begin
  787.          S.Write( _COLW1, Sizeof( _COLW1 ));
  788.          S.Write( W , Sizeof( Word ));
  789.          S.Write( ColHdr[W].Width , Sizeof( Byte ));
  790.       End;
  791.  
  792.       S.Write( _HIDVEC1     ,Sizeof( _HIDVEC1     ));
  793.       S.Write( _TABLE       ,Sizeof( _TABLE       ));
  794.       S.Write( _QRANGE      ,Sizeof( _QRANGE      ));
  795.       S.Write( _PRANGE      ,Sizeof( _PRANGE      ));
  796.       S.Write( _UNFORMATTED ,Sizeof( _UNFORMATTED ));
  797.       S.Write( _FRANGE      ,Sizeof( _FRANGE      ));
  798.       S.Write( _SRANGE      ,Sizeof( _SRANGE      ));
  799.       S.Write( _RRANGE      ,Sizeof( _RRANGE      ));
  800.       S.Write( _MATRIXRANGE ,Sizeof( _MATRIXRANGE ));
  801.       S.Write( _HRANGE      ,Sizeof( _HRANGE      ));
  802.       S.Write( _GPROTECT    ,Sizeof( _GPROTECT    ));
  803.       { Footer }
  804.       { Header }
  805.       S.Write( _MARGINS  ,Sizeof( _MARGINS  ));
  806.       S.Write( _LABELFMT ,Sizeof( _LABELFMT ));
  807.       S.Write( _TITLES   ,Sizeof( _TITLES   ));
  808.       { Cells }
  809.       Cells^.Write(S);      
  810.       S.Write( _EOF ,Sizeof( _EOF ));
  811.    end;   
  812.    S.Done;
  813. end;
  814.  
  815. {  --------------------------------------------------------------------  }
  816.  
  817. Destructor TModel.Done;
  818.  
  819. Begin
  820.    If Cells<>NIL then
  821.    Begin
  822.       Cells^.FreeAll;
  823.       Dispose(Cells, Done);
  824.       Cells:=NIL;
  825.    end;
  826.    Inherited Done;
  827. end;
  828.  
  829. {  --------------------------------------------------------------------  }
  830.  
  831. END.